package com.stox.charting.ui.swing.model;

import java.awt.Graphics;
import java.util.List;

import com.stox.charting.ui.swing.model.uiUnit.UiUnit;

public abstract class Viewport<T> {

	private double maximumValueVisible;
	private double minimumValueVisible;
	private int startIndex;
	private int endIndex;
	private final ChartModel<T> chartModel;
	private List<? extends UiUnit> uiUnits;
	
	public Viewport(ChartModel<T> chartModel) {
		this.chartModel = chartModel;
	}
	
	public void update(int high, int low, int minimum, int maximum){
		List<T> data = chartModel.getData();
		if(data != null && !data.isEmpty()){
			
			startIndex = data.size() - ((low*data.size())/(maximum-minimum)) - 1;
			endIndex = data.size() - ((high*data.size())/(maximum-minimum));
			
			if(endIndex >= startIndex){
				return;
			}
			
			minimumValueVisible = Double.MAX_VALUE;
			maximumValueVisible = Double.MIN_VALUE;
			for(int i = endIndex; i < startIndex; i++){
				T unit = data.get(i);
				double highValue = getHigh(unit);
				double lowValue = getLow(unit);
				if(minimumValueVisible > lowValue){
					minimumValueVisible = lowValue;
				}
				if(maximumValueVisible < highValue){
					maximumValueVisible = highValue;
				}
			}
		}
	}
	
	public void paint(Graphics g){
		if(uiUnits != null && !uiUnits.isEmpty()){
			for(int i = getEndIndex(); i < getStartIndex(); i++){
				uiUnits.get(i).paint(g);
			}
		}
	}
	
	protected abstract double getHigh(T unit);
	
	protected abstract double getLow(T unit);
	
	public double getMaximumValueVisible() {
		return maximumValueVisible;
	}
	public void setMaximumValueVisible(double maximumValueVisible) {
		this.maximumValueVisible = maximumValueVisible;
	}
	public double getMinimumValueVisible() {
		return minimumValueVisible;
	}
	public void setMinimumValueVisible(double minimumValueVisible) {
		this.minimumValueVisible = minimumValueVisible;
	}
	public int getStartIndex() {
		return startIndex;
	}
	public void setStartIndex(int startIndex) {
		this.startIndex = startIndex;
	}
	public int getEndIndex() {
		return endIndex;
	}
	public void setEndIndex(int endIndex) {
		this.endIndex = endIndex;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + endIndex;
		long temp;
		temp = Double.doubleToLongBits(maximumValueVisible);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(minimumValueVisible);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + startIndex;
		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Viewport<T> other = (Viewport<T>) obj;
		if (endIndex != other.endIndex)
			return false;
		if (Double.doubleToLongBits(maximumValueVisible) != Double
				.doubleToLongBits(other.maximumValueVisible))
			return false;
		if (Double.doubleToLongBits(minimumValueVisible) != Double
				.doubleToLongBits(other.minimumValueVisible))
			return false;
		if (startIndex != other.startIndex)
			return false;
		return true;
	}

	public ChartModel<T> getChartModel() {
		return chartModel;
	}
	
	public List<? extends UiUnit> getUiUnits() {
		return uiUnits;
	}
	
	public void setUiUnits(List<? extends UiUnit> uiUnits) {
		this.uiUnits = uiUnits;
		chartModel.fireChartModelChangedEvent("uiUnits");
	}
	
}
